﻿using MgSoft.Excel.Model;
using MgSoft.Excel.Model.Excel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Linq;
using System.Diagnostics;
using MgSoft.Excel.Model.Template;

namespace MgSoft.Excel.Util
{
    public static class MgSheetOledbUtil
    {
        public static MgSheet ConvertToMgSheet(DataTable table, TemplateConfig templateConfig, List<ExcelErrorMessage> errorMessages)
        {
            var keyCellConfig = templateConfig.GetKeyCellConfig();

            MgSheet mgSheet = new MgSheet();

            //转换关键数据
            ConvertDataKey(table, mgSheet, keyCellConfig, errorMessages);
            ConvertDataExtX(table, mgSheet, templateConfig, errorMessages);
            ConvertDataExtY(table, mgSheet, templateConfig, errorMessages);
            ConvertDataExtC(table, mgSheet, templateConfig, errorMessages);

            return mgSheet;

        }

        private static void ConvertDataExtC(DataTable dataTable, MgSheet mgSheet, TemplateConfig templateConfig, List<ExcelErrorMessage> errorMessages)
        {
            var dataTemplateConfig = templateConfig.TemplateCellConfigs.Where(p => p.IsKey == false && p.Ext == Ext.C).ToList();
            foreach (var item in dataTemplateConfig)
            {
                var cell = dataTable.Rows[item.StartRow][item.ColumnIndex];
                mgSheet.Add(new MgCell()
                {
                    CellDataType = item.Type,
                    ColumnIndex = item.ColumnIndex,
                    ColumnName = item.Name,
                    RowIndex = item.StartRow,
                    Value = GetCellValue(cell, item)
                });
            }
        }

        private static void ConvertDataExtY(DataTable dataTable, MgSheet mgSheet, TemplateConfig templateConfig, List<ExcelErrorMessage> errorMessages)
        {
            //todo
        }

        private static void ConvertDataExtX(DataTable dataTable, MgSheet mgSheet, TemplateConfig templateConfig, List<ExcelErrorMessage> errorMessages)
        {
            var dataTemplateConfig = templateConfig.TemplateCellConfigs.Where(p => p.IsKey == false && p.Ext == Ext.X).ToList();
            int startRowIndex = mgSheet.StartRowIndex;
            int maxRowIndex = mgSheet.MaxRowIndex;

            foreach (var item in dataTemplateConfig)
            {
                var columnIndex = item.ColumnIndex;

                for (int rowIndex = startRowIndex; rowIndex <= maxRowIndex; rowIndex++)
                {
                    //数据校验错误信息
                    List<ExcelErrorMessage> convertErrorMessages = new List<ExcelErrorMessage>();
                    var cell = dataTable.Rows[rowIndex][columnIndex];

                    CheckCellValueByCellConfig(cell, item, rowIndex, columnIndex, convertErrorMessages);//校验数据

                    //校验成功则把cell转换为MgCell
                    if (convertErrorMessages.Count == 0)
                    {
                        mgSheet.Add(new MgCell()
                        {
                            CellDataType = item.Type,
                            ColumnIndex = columnIndex,
                            ColumnName = item.Name,
                            RowIndex = rowIndex,
                            Value = GetCellValue(cell, item)
                        });
                    }
                    else
                    {
                        errorMessages.AddRange(convertErrorMessages);
                    }
                }
            }
        }

        /// <summary>
        /// 转换关键数据
        /// </summary>
        /// <param name="dataTable"></param>
        /// <param name="mgSheet"></param>
        /// <param name="keyCellConfig"></param>
        /// <param name="errorMessages"></param>
        private static void ConvertDataKey(DataTable dataTable, MgSheet mgSheet, TemplateCellConfig keyCellConfig, List<ExcelErrorMessage> errorMessages)
        {

            int rowIndex = keyCellConfig.StartRow;
            int columnIndex = keyCellConfig.ColumnIndex;

            if (rowIndex > dataTable.Rows.Count) return;//表格没有数据
            if (columnIndex > dataTable.Rows[0].ItemArray.Length) return;

            ((IMgSheet)mgSheet).SetStartRowIndex(rowIndex);

            Stopwatch stopwatch = new Stopwatch();
            int sheetRowIndex = rowIndex;
            while (sheetRowIndex < dataTable.Rows.Count)
            {
                try
                {
                    stopwatch.Start();

                    //数据校验错误信息
                    List<ExcelErrorMessage> convertErrorMessages = new List<ExcelErrorMessage>();
                    var cell = dataTable.Rows[sheetRowIndex][columnIndex];

                    //如果读不到数据则结束循环
                    if (cell == null || string.IsNullOrEmpty(cell.ToString()))
                    {
                        break;
                    }

                    CheckCellValueByCellConfig(cell, keyCellConfig, rowIndex, columnIndex, convertErrorMessages);//校验数据

                    stopwatch.Stop();

                    stopwatch.Reset();
                    stopwatch.Start();

                    //校验成功则把cell转换为MgCell
                    if (convertErrorMessages.Count == 0)
                    {
                        mgSheet.Add(new MgCell()
                        {
                            CellDataType = keyCellConfig.Type,
                            ColumnIndex = columnIndex,
                            ColumnName = keyCellConfig.Name,
                            RowIndex = sheetRowIndex,
                            Value = GetCellValue(cell, keyCellConfig)
                        });
                    }
                    else
                    {
                        errorMessages.AddRange(convertErrorMessages);
                    }

                    ((IMgSheet)mgSheet).SetMaxRowIndex(sheetRowIndex);
                    sheetRowIndex++;
                    stopwatch.Stop();
                    stopwatch.Reset();
                }
                catch(Exception e)
                {
                    System.Diagnostics.Debug.WriteLine($"转换第{sheetRowIndex}行，出错");
                    throw e;
                }
            }

            stopwatch.Stop();
            System.Diagnostics.Debug.WriteLine($"转换MgSheet对像用时:{stopwatch.ElapsedMilliseconds/1000}秒");
        }

        private static object GetCellValue(object cell, TemplateCellConfig cellConfig)
        {
            object returnValue;

            if (cell == null) return null;

            //var cellValue = GetCellValue(cell);
            switch (cellConfig.Type)
            {
                case CellDataType.String:
                    returnValue = cell.ToString();
                    break;
                case CellDataType.Int:
                    returnValue = Convert.ToInt32(cell);
                    break;
                case CellDataType.Double:
                    returnValue = Convert.ToDouble(cell);
                    break;
                case CellDataType.Decimal:
                    returnValue = Convert.ToDecimal(cell);
                    break;
                case CellDataType.Date:
                    returnValue = Convert.ToDateTime(cell);              
                    break;
                case CellDataType.NullableInt:
                    if (Int32.TryParse(cell.ToString(), out var nullableInt))
                        returnValue = nullableInt;
                    else
                        returnValue = null;
                    break;
                case CellDataType.NullableDouble:
                    if (double.TryParse(cell.ToString(), out var nullableDouble))
                        returnValue = nullableDouble;
                    else
                        returnValue = null;
                    break;
                case CellDataType.NullableDecimal:
                    if (double.TryParse(cell.ToString(), out var nullableDecimal))
                        returnValue = nullableDecimal;
                    else
                        returnValue = null;
                    break;
                case CellDataType.NullableDate:
                    if (DateTime.TryParse(cell.ToString(), out var nullableDateTime))
                        returnValue = nullableDateTime;
                    else
                        returnValue = null;
                    break;
                default: throw new MgExcelException($"[{cellConfig.Type.ToString()}]未定义的类型");
            }
            return returnValue;
        }


        private static void CheckCellValueByCellConfig(object cell, TemplateCellConfig keyCellConfig, int rowIndex, int columnIndex, List<ExcelErrorMessage> errorMessages)
        {
            CheckIsRequired(cell, keyCellConfig, rowIndex, columnIndex, errorMessages);
            CheckType(cell, keyCellConfig, rowIndex, columnIndex, errorMessages);
            //CehckIsRequire(cell, keyCellConfig);
        }

        private static void CheckType(object cell, TemplateCellConfig keyCellConfig, int rowIndex, int columnIndex, List<ExcelErrorMessage> errorMessages)
        {
            //数据为空则不检查类型
            if (cell == null)
            {
                return;
            }

            try
            {
                GetCellValue(cell, keyCellConfig);
            }
            catch (Exception e)
            {
                string message = $"类型应为[{CellDataTypeUtil.GetDataTypeCaption(keyCellConfig.Type)}]";
                errorMessages.Add(new ExcelErrorMessage(rowIndex, columnIndex, message));
            }
        }

        private static void CheckIsRequired(object cell, TemplateCellConfig keyCellConfig, int rowIndex, int columnIndex, List<ExcelErrorMessage> errorMessages)
        {
            //不允许为空
            if (keyCellConfig.IsRequired)
            {
                if (string.IsNullOrEmpty(cell?.ToString()))
                {
                    var columnCaption = keyCellConfig.Caption;
                    errorMessages.Add(new ExcelErrorMessage(rowIndex, columnIndex, $@"【{columnCaption}】列没有值"));
                }
            }
        }

        //private static void convertX()
        //{
        //    throw new NotImplementedException();
        //}
    }
}
